#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;

class CowString{
public:
    CowString();
    ~CowString();
    CowString(const CowString & rhs);
    CowString(const char * pstr);
    CowString & operator=(const CowString & rhs);

    char & operator[](size_t idx);

    const char * c_str() const{ return _pstr; }
    size_t size() const{ return strlen(_pstr); }
    int use_count() { return *(int*)(_pstr - kRefcountLength); }
    friend
        ostream & operator<<(ostream & os, const CowString & rhs);
private:
    char * malloc(const char * pstr = nullptr){
        if(pstr){
            return new char[strlen(pstr) + kRefcountLength + 1]()+ kRefcountLength;
        }else{
            return new char[1 + kRefcountLength]() + kRefcountLength;
        }
    }

    void release(){
        decreaseRefcount();
        if(use_count() == 0){
            delete [] (_pstr - kRefcountLength);
            _pstr = nullptr;
            cout << "delete heap" << endl;
        }
    }

    void initRefcount(){
        *(int*)(_pstr - kRefcountLength) = 1;
    }

    void increaseRefcount(){
        ++*(int*)(_pstr - kRefcountLength);
    }

    void decreaseRefcount(){
        --*(int*)(_pstr - kRefcountLength);
    }

    static const int kRefcountLength = 4;
    char * _pstr;
};

ostream & operator<<(ostream & os, const CowString & rhs){
    os << rhs._pstr ;
    return os;
}

CowString::CowString()
    : _pstr(malloc())
{
    cout << "CowString()" << endl; 
    initRefcount();
}

CowString::~CowString(){
    release();
}


CowString::CowString(const CowString & rhs)
    : _pstr(rhs._pstr)//浅拷贝
{
    increaseRefcount();
    cout << "CowString(const CowString&)" << endl;
}


CowString::CowString(const char * pstr)
    : _pstr(malloc(pstr))
{
    cout << "CowString(const char *)" << endl;
    strcpy(_pstr,pstr);
    initRefcount();
}

CowString & CowString::operator=(const CowString & rhs){
    if(this != &rhs){ //1.还需要考虑自复制
        cout << "CowString& operator=(const CowString&)" << endl;
        release(); //2.判断是否回收，原本空间的引用计数-1
        _pstr = rhs._pstr;  //3.浅拷贝
        increaseRefcount();
    }
    return *this;
}

char & CowString::operator[](size_t idx){
    if(idx < size()){
        return _pstr[idx];
    }else{
        cout << "out of range" << endl;
        static char nullchar = '\0';
        return nullchar;
    }
}

void test0(){
    CowString str1;
    cout << str1.use_count() << endl;
    CowString str2 = str1;
    cout << "str1:" << str1 << endl;
    cout << "str2:" << str2 << endl;
    cout << str1.use_count() << endl;
    cout << str2.use_count() << endl;

    cout << "#############" << endl;
    CowString str3("hello");
    cout << "str3:" << str3 << endl;
    cout << str3.use_count() << endl;
    CowString str4 = str3;
    cout << "str3:" << str3 << endl;
    cout << "str4:" << str4 << endl;
    cout << str3.use_count() << endl;
    cout << str4.use_count() << endl;

    cout << "#############" << endl;
    str1 = str3;
    cout << "str1:" << str1 << endl;
    cout << "str2:" << str2 << endl;
    cout << "str3:" << str3 << endl;
    cout << "str4:" << str4 << endl;
    cout << str1.use_count() << endl;
    cout << str2.use_count() << endl;
    cout << str3.use_count() << endl;
    cout << str4.use_count() << endl;

    cout << "#############" << endl;
    //读操作不需要重新开辟空间
    cout << str1[0] << endl;
    //写操作应该重新开辟空间
    //也就是写时复制
    str1[0] = 'H';
    cout << str1[0] << endl;
    cout << str3[0] << endl;
    cout << str4[0] << endl;


    //没有优化余地
    //不能共享空间
    //只有复制的时候，确定内容是相同的
    //才会共享空间
    /* CowString str5("hello"); */
    /* CowString str6("hello"); */


}

int main(void){
    test0();
    return 0;
}
